home *** CD-ROM | disk | FTP | other *** search
- /* Internet Telnet client
- * Copyright 1991 Phil Karn, KA9Q
- */
- /* Mods by PA0GRI */
- /* Mods by KO4KS */
- #ifdef MSDOS
- #include <conio.h>
- #endif
- #include "global.h"
- #include "commands.h"
- #include "mbuf.h"
- #include "socket.h"
- #include "telnet.h"
- #include "netuser.h"
- #include "usock.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: telnet.c,v 1.23 1997/08/19 01:19:22 root Exp root $";
- #endif
-
- #if !defined(TNOS_68K) && !defined(UNIX)
- void displayStatLine (int offset, int phase, int onlymarquee);
- extern unsigned char SCREENwidth, SCREENlength;
- #endif
-
- #ifdef CONVERS
- extern char CConsole[];
- #endif
-
- static void dontopt (struct telnet *tn,int opt);
- static void tel_output (int unused,void *p1,void *p2);
- static void answer (struct telnet *tn,int r1,int r2);
- static int filemode (FILE * fp, int mode);
- static void doopt (struct telnet *tn,int opt);
- static void willopt (struct telnet *tn,int opt);
- static void wontopt (struct telnet *tn,int opt);
-
- #ifndef CTLZ
- #define CTLZ 26
- #endif
-
- static int Refuse_echo = 0;
- static int Tn_cr_mode = 0; /* if true turn <cr> to <cr-nul> */
- static int usesplit = 0; /* kludge for doconf */
-
- static char *conversinit;
-
-
- #ifdef DEBUG
- char *T_options[] =
- {
- "Transmit Binary",
- "Echo",
- "",
- "Suppress Go Ahead",
- "",
- "Status",
- "Timing Mark"
- };
- #endif
-
-
-
- #ifdef MAILBOX
- /* Execute user BBS command */
- int
- dobbs (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
- {
- struct session *sp;
- struct sockaddr_in fsocket;
-
- /*Make sure this comes from console - WG7J*/
- if (Curproc->input != Command->input)
- return 0;
-
- /* Allocate a session descriptor */
- if ((sp = newsession ("Local PBBS access", TELNET, 0)) == NULLSESSION) {
- tputs (TooManySessions);
- return 1;
- }
- chname (Curproc, "Local PBBS access");
- fsocket.sin_family = AF_INET;
- fsocket.sin_port = IPPORT_TELNET;
-
- fsocket.sin_addr.s_addr = 0x7f000001L; /* 127.0.0.1 the loopback interface */
- if ((sp->s = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
- tputs (Nosock);
- (void) keywait (NULLCHAR, 1);
- freesession (sp);
- return 1;
- }
- return tel_connect (sp, (char *) &fsocket, SOCKSIZE);
- }
- #endif /*MAILBOX*/
-
-
-
-
- #ifdef RLOGINSERV
- /* Execute remote login command */
- int
- dorlogin (int argc OPTIONAL, char *argv[], void *p)
- {
- free (argv[0]);
- argv[0] = strdup ("telnet");
- if (argv[2])
- free (argv[2]);
- argv[2] = strdup ("513");
- if (!argv[1])
- argv[1] = strdup (Hostname);
- usesplit = 1;
- return dotelnet (3, argv, p);
- }
- #endif
-
-
-
- #ifdef ALLSESSIONS
- #ifdef CONVERS
- /* Execute user conference command */
- int
- doconf (int argc OPTIONAL, char *argv[], void *p)
- {
- char buf[32], buf2[96];
- char *cptr;
-
- if (CConsole[0])
- (void) strlwr (CConsole); /* just in case */
-
- sprintf (buf, "/NA %s %s\n", (CConsole[0]) ? CConsole : "sysop", (argc > 2 && argv[2]) ? argv[2] : "-1");
-
- free (argv[0]);
- argv[0] = strdup ("telnet");
-
- if (argc > 1 && !argv[1]) {
- strncpy (buf2, Hostname, 96);
- cptr = strchr (buf2, '.');
- if (cptr)
- *cptr = 0;
- (void) strlwr (buf2);
- argv[1] = strdup (buf2);
- }
-
- if (argc > 2 && argv[2])
- free (argv[2]);
- argv[2] = strdup ("3600");
-
- conversinit = buf; /*lint !e789 */
- usesplit = 1;
- return dotelnet (3, argv, p);
- }
- #endif /* CONVERS */
-
-
- #ifdef ALLSERV
- extern void clrchatline (struct session * sp);
- #endif
-
- /* Execute user telnet command */
- int
- dotelnet (int argc, char *argv[], void *p OPTIONAL)
- {
- struct session *sp;
- struct sockaddr_in fsocket;
- int split;
-
- split = usesplit;
- usesplit = 0;
-
- /*Make sure this comes from console - WG7J*/
- if (Curproc->input != Command->input)
- return 0;
-
- #ifdef ALLSERV
- if ((strlen (argv[0]) > 1) && (argv[0][1] == 't')) /* tty-link command */
- split = 1;
- #endif
-
- /* Allocate a session descriptor */
- if ((sp = newsession (argv[1], TELNET, split)) == NULLSESSION) {
- tputs (TooManySessions);
- return 1;
- }
- fsocket.sin_family = AF_INET;
- if (argc < 3) {
- if (split)
- fsocket.sin_port = IPPORT_TTYLINK;
- else
- fsocket.sin_port = IPPORT_TELNET;
- } else
- fsocket.sin_port = (int16) atoip (argv[2]);
-
- tprintf ("Resolving %s... ", sp->name);
- if ((fsocket.sin_addr.s_addr = resolve (sp->name)) == 0) {
- tprintf (Badhost, sp->name);
- (void) keywait (NULLCHAR, 1);
- freesession (sp);
- return 1;
- }
- if ((sp->s = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
- tputs (Nosock);
- (void) keywait (NULLCHAR, 1);
- freesession (sp);
- return 1;
- }
- return tel_connect (sp, (char *) &fsocket, SOCKSIZE);
- }
- #endif
-
-
-
- /* Generic interactive connect routine, used by Telnet, AX.25, NET/ROM */
- int
- tel_connect (struct session *sp, char *fsocket, int len)
- {
- unsigned int theindex;
- struct telnet tn;
-
- theindex = (unsigned int) (sp - Sessions);
- memset ((char *) &tn, 0, sizeof (tn));
- tn.eolmode = (char) Tn_cr_mode;
- tn.session = sp; /* Upward pointer */
- sp->cb.telnet = &tn; /* Downward pointer */
- (void) sockmode (sp->s, SOCK_ASCII); /* Default to ascii mode */
-
- /* place the initial cursor in the input area of split screens */
- #ifdef ALLSERV
- if (sp->split) {
- clrchatline (sp);
- clrscr ();
- }
- #endif
-
- tprintf ("Trying %s...\n", psocket ((struct sockaddr *) fsocket));
- if (connect (sp->s, fsocket, len) == -1) {
- tprintf ("%s session %u failed: %s errno %d\n",
- Sestypes[sp->type], theindex, sockerr (sp->s), errno);
-
- (void) keywait (NULLCHAR, 1);
- freesession (sp);
- return 1;
- }
- tprintf ("%s session ", Sestypes[sp->type]);
- tprintf ("%u connected to %s\n", theindex, sp->name);
- tnrecv (&tn);
- return 0;
- }
-
-
-
- /* Telnet input routine, common to both telnet and ttylink */
- void
- tnrecv (struct telnet *tn)
- {
- int c, s, theindex;
- struct session *sp;
- char const *cp;
- #if !defined(TNOS_68K) && !defined(UNIX)
- struct text_info tr;
- unsigned char attr;
- #endif
- #ifdef LZW
- int bits, mode;
- struct usock *up;
- #endif
-
- sp = tn->session;
- s = sp->s;
-
- theindex = sp - Sessions;
-
- /* Fork off the transmit process */
- sp->proc1 = newproc ("tel_out", 1024, tel_output, 0, tn, NULL, 0);
-
- /* Process input on the connection */
- while ((c = recvchar (s)) != EOF) {
- if (c != IAC) {
- tputc (uchar(c));
- continue;
- }
- /* IAC received, get command sequence */
- c = recvchar (s);
- switch (c) {
- case WILL:
- c = recvchar (s);
- willopt (tn, c);
- break;
- case WONT:
- c = recvchar (s);
- wontopt (tn, c);
- break;
- case DO:
- c = recvchar (s);
- doopt (tn, c);
- break;
- case DONT:
- c = recvchar (s);
- dontopt (tn, c);
- break;
- #ifdef LZW
- case COMPRESSED:
- mode = recvchar (s);
- bits = recvchar (s);
- mode = (mode == 'f') ? 1 : 0;
- if (bits < 9 || bits > 16)
- break;
- if ((up = itop (s)) == NULLUSOCK)
- break;
- if (up->zout == NULLLZW)
- lzwinit (s, bits, mode);
- else
- lzwfree (up);
- break;
- #endif
- case CLEARSCREEN:
- #if !defined(TNOS_68K) && !defined(UNIX)
- if (!sp->split) {
- window (1, 1, SCREENwidth, SCREENlength);
- clrscr (); /* clear the screen */
- window (1, SCREENlength - 1, SCREENwidth, SCREENlength); /* changed 1,1->1,24 */
- gettextinfo (&tr);
- attr = ((tr.attribute & 0x0f) << 4) + ((tr.attribute & 0x70) >> 4);
- textattr (attr);
- clrscr ();
- cputs ("_\b");
- window (1, 1 + sp->screen->statline, SCREENwidth, SCREENlength - 2);
- textattr (tr.attribute);
- sp->split = 1;
- if (sp->screen->statline)
- displayStatLine (0, 1, 0);
- }
- #endif
- break;
- case CLEARSPLIT:
- #if !defined(TNOS_68K) && !defined(UNIX) && defined(ALLSERV)
- clrchatline (sp);
- #endif
- break;
- case IAC: /* Escaped IAC */
- tputc (IAC);
- break;
- default:
- break;
- }
- }
- /* A close was received from the remote host.
- * Notify the user, kill the output task and wait for a response
- * from the user before freeing the session.
- */
- (void) sockmode (sp->output, SOCK_ASCII); /* Restore newline translation */
- cp = sockerr (s);
- tprintf ("%s session %u", Sestypes[sp->type], theindex);
- tprintf (" closed: %s\n", cp != NULLCHAR ? cp : "EOF");
- killproc (sp->proc1);
- sp->proc1 = NULLPROC;
- close_s (sp->s);
- sp->s = -1;
- (void) keywait (NULLCHAR, 1);
- freesession (sp);
- }
-
-
-
- /* User telnet output task, started by user telnet command */
- static void
- tel_output (int unused OPTIONAL, void *tn1, void *p OPTIONAL)
- {
- struct session *sp;
- int c;
- struct telnet *tn;
-
- tn = (struct telnet *) tn1;
- sp = tn->session;
-
- if (conversinit) {
- usprintf (sp->s, conversinit);
- conversinit = 0;
- }
- /* Send whatever's typed on the terminal */
- while ((c = recvchar (sp->input)) != EOF) {
- usputc (sp->s, uchar(c));
- if (!tn->remote[TN_ECHO] && sp->record != NULLFILE)
- (void) putc (c, sp->record);
-
- /* By default, output is transparent in remote echo mode.
- * If eolmode is set, turn a cr into cr-null.
- * This can only happen when in remote echo (raw) mode, since
- * the tty driver normally maps \r to \n in cooked mode.
- */
- if (c == '\r' && tn->eolmode)
- usputc (sp->s, '\0');
-
- if (tn->remote[TN_ECHO])
- usflush (sp->s);
- }
- /* Make sure our parent doesn't try to kill us after we exit */
- sp->proc1 = NULLPROC;
- }
-
-
-
- int
- doechomode (int argc, char *argv[], void *p OPTIONAL)
- {
- if (argc < 2) {
- if (Refuse_echo)
- tputs ("Refuse\n");
- else
- tputs ("Accept\n");
- } else {
- if (argv[1][0] == 'r')
- Refuse_echo = 1;
- else if (argv[1][0] == 'a')
- Refuse_echo = 0;
- else
- return -1;
- }
- return 0;
- }
-
-
-
- /* set for unix end of line for remote echo mode telnet */
- int
- doeol (int argc, char *argv[], void *p OPTIONAL)
- {
- if (argc < 2) {
- if (Tn_cr_mode)
- tputs ("null\n");
- else
- tputs ("standard\n");
- } else {
- if (argv[1][0] == 'n')
- Tn_cr_mode = 1;
- else if (argv[1][0] == 's')
- Tn_cr_mode = 0;
- else {
- tprintf ("Usage: %s [standard|null]\n", argv[0]);
- return -1;
- }
- }
- return 0;
- }
-
-
-
- /* The guts of the actual Telnet protocol: negotiating options */
- void
- willopt (struct telnet *tn, int opt)
- {
- int ack;
-
- #ifdef DEBUG
- tcmdprintf ("recv: will ");
- if (uchar (opt) <= NOPTIONS)
- tcmdprintf ("%s\n", T_options[opt]);
- else
- tcmdprintf ("%u\n", opt);
- #endif
-
- switch (uchar (opt)) {
- case TN_TRANSMIT_BINARY:
- case TN_ECHO:
- case TN_SUPPRESS_GA:
- if (tn->remote[uchar (opt)] == 1)
- return; /* Already set, ignore to prevent loop */
- if (uchar (opt) == TN_ECHO) {
- if (Refuse_echo) {
- /* User doesn't want to accept */
- ack = DONT;
- break;
- } else {
- /* Put tty into raw mode */
- tn->session->ttystate.edit = 0;
- tn->session->ttystate.echo = 0;
- (void) sockmode (tn->session->s, SOCK_BINARY);
- (void) sockmode (tn->session->input, SOCK_BINARY);
- (void) sockmode (tn->session->output, SOCK_BINARY);
- if (tn->session->record != NULLFILE)
- (void) filemode (tn->session->record, SOCK_BINARY);
-
- }
- }
- tn->remote[uchar (opt)] = 1;
- ack = DO;
- break;
- default:
- ack = DONT; /* We don't know what he's offering; refuse */
- }
- answer (tn, ack, opt);
- }
-
-
-
- void
- wontopt (struct telnet *tn, int opt)
- {
- #ifdef DEBUG
- tcmdprintf ("recv: wont ");
- if (uchar (opt) <= NOPTIONS)
- tcmdprintf ("%s\n", T_options[uchar (opt)]);
- else
- tcmdprintf ("%u\n", uchar (opt));
- #endif
- if (uchar (opt) <= NOPTIONS) {
- if (tn->remote[uchar (opt)] == 0)
- return; /* Already clear, ignore to prevent loop */
- tn->remote[uchar (opt)] = 0;
- if (uchar (opt) == TN_ECHO) {
- /* Put tty into cooked mode */
- tn->session->ttystate.edit = 1;
- tn->session->ttystate.echo = 1;
- (void) sockmode (tn->session->s, SOCK_ASCII);
- (void) sockmode (tn->session->input, SOCK_ASCII);
- (void) sockmode (tn->session->output, SOCK_ASCII);
- if (tn->session->record != NULLFILE)
- (void) filemode (tn->session->record, SOCK_ASCII);
- }
- }
- answer (tn, DONT, opt); /* Must always accept */
- }
-
-
-
- static void
- doopt (struct telnet *tn, int opt)
- {
- int ack;
-
- #ifdef DEBUG
- tcmdprintf ("recv: do ");
- if (uchar (opt) <= NOPTIONS)
- tcmdprintf ("%s\n", T_options[uchar (opt)]);
- else
- tcmdprintf ("%u\n", uchar (opt));
- #endif
- switch (uchar (opt)) {
- case TN_SUPPRESS_GA:
- if (tn->local[uchar (opt)] == 1)
- return; /* Already set, ignore to prevent loop */
- tn->local[uchar (opt)] = 1;
- ack = WILL;
- break;
- default:
- ack = WONT; /* Don't know what it is */
- }
- answer (tn, ack, opt);
- }
-
-
-
- static void
- dontopt (struct telnet *tn, int opt)
- {
- #ifdef DEBUG
- tcmdprintf ("recv: dont ");
- if (uchar (opt) <= NOPTIONS)
- tcmdprintf ("%s\n", T_options[uchar (opt)]);
- else
- tcmdprintf ("%u\n", uchar (opt));
- #endif
- if (uchar (opt) <= NOPTIONS) {
- if (tn->local[uchar (opt)] == 0) /* Already clear, ignore to prevent loop */
- return;
-
- tn->local[uchar (opt)] = 0;
- }
- answer (tn, WONT, opt);
- }
-
-
-
- static void
- answer (struct telnet *tn, int r1, int r2)
- {
- char s[3];
-
- #ifdef DEBUG
- switch (r1) {
- case WILL:
- tcmdprintf ("sent: will ");
- break;
- case WONT:
- tcmdprintf ("sent: wont ");
- break;
- case DO:
- tcmdprintf ("sent: do ");
- break;
- case DONT:
- tcmdprintf ("sent: dont ");
- break;
- }
- if (r2 <= NOPTIONS)
- tcmdprintf ("%s\n", T_options[r2]);
- else
- tcmdprintf ("%u\n", r2);
- #endif
-
- s[0] = (char) IAC;
- s[1] = (char) r1;
- s[2] = (char) r2;
- (void) send (tn->session->s, s, 3, 0);
- }
-
-
-
- static int
- filemode (FILE *fp OPTIONAL, int mode OPTIONAL)
- {
- return 0;
- }
-
-